package cn.kennylee.codehub.common.das;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import org.springframework.lang.NonNull;

import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * <p> 查询条件 </p>
 * <p>Created on 2024/12/8.</p>
 *
 * @author kennylee
 * @since 0.0.1
 */
public enum CondOperation {
    /**
     * 等于
     */
    EQ(CollUtil.newHashSet()),
    /**
     * 不等于
     */
    NE(CollUtil.newHashSet()),
    /**
     * 大于
     */
    GT(CollUtil.newHashSet()),
    /**
     * 大于等于
     */
    GE(CollUtil.newHashSet()),
    /**
     * 小于
     */
    LT(CollUtil.newHashSet()),
    /**
     * 小于等于
     */
    LE(CollUtil.newHashSet()),
    /**
     * not like
     */
    NOT_LIKE(CollUtil.newHashSet()),
    /**
     * 前匹配模糊查询：%aaa
     */
    PRE_LIKE(CollUtil.newHashSet()),
    /**
     * 后匹配模糊查询：aaa%
     */
    SUF_LIKE(CollUtil.newHashSet()),
    /**
     * like,部分匹配模糊查询：%aaa%
     */
    LIKE(CollUtil.newHashSet(NOT_LIKE, PRE_LIKE, SUF_LIKE)),
    /**
     * not in
     */
    NOT_IN(CollUtil.newHashSet()),
    /**
     * in
     */
    IN(CollUtil.newHashSet(NOT_IN)),
    /**
     * is null
     */
    IS_NULL(CollUtil.newHashSet()),
    /**
     * is not null
     */
    IS_NOT_NULL(CollUtil.newHashSet()),
    ;

    /**
     * 排查的条件
     */
    private final Set<CondOperation> excludeCondOperations;

    /**
     * 范围查询字段后缀
     */
    public static final Set<String> RANG_SUFFIX_FIELDS = new HashSet<>(Arrays.asList(GT.name(), GE.name(), LT.name(), LE.name()));

    CondOperation(Set<CondOperation> excludeCondOperations) {
        this.excludeCondOperations = excludeCondOperations;
    }

    public String lowerCase() {
        return this.name().toLowerCase();
    }

    /**
     * 判断入参字符串是否以枚举操作符结尾
     * <p>注：</p>
     * <ol>
     *     <li>字段名会转成下划线风格判断</li>
     *     <li>忽略大小写</li>
     * </ol>
     *
     * @param fieldName 字段名
     * @return 是否以枚举操作符结尾
     */
    public boolean isEndWithIgnoreCase(@NonNull String fieldName) {

        List<String> splitFieldNames = Arrays.asList(StrUtil.toUnderlineCase(fieldName).split("_"));

        int maxIndex = this.name().split("_").length;

        String suffixFieldName = splitFieldNames.size() > maxIndex ?
            StrUtil.join("_", splitFieldNames.subList(splitFieldNames.size() - maxIndex, splitFieldNames.size())) :
            splitFieldNames.get(0);

        return StrUtil.equals(suffixFieldName, this.lowerCase()) &&
            // 同时不能以排除的操作符结尾
            this.excludeCondOperations.stream().noneMatch(excludeCondOperation -> excludeCondOperation.isEndWithIgnoreCase(fieldName));
    }

    /**
     * 截取去掉操作标识后的字段名，下划线风格
     *
     * @param fieldName 字段名
     * @return 截取去掉操作标识后的字段名，下划线风格
     */
    public String subFieldNameUnderlineCase(@NonNull String fieldName) {
        if (this == EQ) {
            if (EQ.isEndWithIgnoreCase(fieldName)) {
                return StrUtil.subBefore(StrUtil.toUnderlineCase(fieldName), "_" + this.lowerCase(), true);
            }
            return StrUtil.toUnderlineCase(fieldName);
        }
        return StrUtil.subBefore(StrUtil.toUnderlineCase(fieldName), "_" + this.lowerCase(), true);
    }

    /**
     * 截取去掉操作标识后的字段名，驼峰风格
     *
     * @param fieldName 字段名
     * @return 截取去掉操作标识后的字段名，驼峰风格
     */
    public String subFieldNameCamelCase(@NonNull String fieldName) {
        return StrUtil.toCamelCase(subFieldNameUnderlineCase(fieldName));
    }

    /**
     * 判断字段是否为范围查询命名，忽略大小写
     *
     * @param fieldName 字段名
     * @return 是否为范围查询命名
     */
    public static boolean isRangeField(@NonNull String fieldName) {
        return RANG_SUFFIX_FIELDS.stream().anyMatch(rangeSuffixFieldName -> StrUtil.endWithAnyIgnoreCase(StrUtil.toUnderlineCase(fieldName), rangeSuffixFieldName));
    }

    /**
     * 根据字段名匹配操作符
     *
     * @param propName 字段名
     * @return 操作符，默认为等于
     */
    @NonNull
    public static CondOperation match(@NonNull String propName) {
        for (CondOperation operation : CondOperation.values()) {
            if (operation.isEndWithIgnoreCase(propName)) {
                return operation;
            }
        }
        return EQ;
    }
}
